package com.xinyue.ext.reader.dao;

import java.util.ArrayList;
import java.util.List;

import org.dom4j.Element;
import org.dom4j.Node;

import com.xinyue.ext.data.FinderData;
import com.xinyue.ext.exception.FinderException;
import com.xinyue.ext.reader.ParamHolder;
import com.xinyue.ext.util.StringUtil;

public class QueryProcess extends DaoContext{
	//私有构造器
	private QueryProcess() {
	}
	//内部类
	private static class SingletonHolder{
        private static QueryProcess instance = new QueryProcess();  
    }
	/**
	 * 获得对象实例
	 */
	public static QueryProcess getInstance(ParamHolder holder) {
		DaoContext.holder = holder;
		return SingletonHolder.instance;
	}

	
	/**
	 * 读取query标签数据
	 * param finder finder标签
	 */
	@SuppressWarnings("unchecked")
	@Override
	public void read(Element finder) throws FinderException {
		List<Element> qs = finder.elements(query_);
		
		//存在query标签
		if(qs != null && qs.size() > 0) {
			List<FinderData> finders = new ArrayList<FinderData>();
			
			for (Element query: qs) {
				FinderData find = commonRead(query);
				//返回值、强制类型转换、是否单个结果集处理
				returnType(query.attributeValue(returnType_), find, query_type);
				//入参、paramSetter以及hql语句预处理
				String where = queryProcess(query, find);
				//order-by语句预处理
				String order = orderProcess(query);
				
				String state = "from " + holder.getEntity().getClassName() + " " + where + " " + order;
				find.setState(state);
				find.setConvert(true);
				
				finders.add(find);
			}
			
			holder.getEntity().getDao().setQuerys(finders);
		}
	}

	
	/**
	 * 入参、paramSetter以及hql语句预处理
	 * param query标签
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private String queryProcess(Element query, FinderData find) throws FinderException {
		List<Element> columns = query.elements(query_column_);
		if(columns == null || columns.size() == 0) {
			throw new FinderException("query标签必须定义query-column子标签", holder.getException());
		}
		
		String param = "";
		String where = "";
		List<String> setter = new ArrayList<String>();
		
		for (Element column: columns) {
			String name = column.attributeValue(name_);
			if(StringUtil.isNull(name)) {
				throw new FinderException("query-column标签未定义name属性或其值为空", holder.getException());
			}else {
				//验证query-column数据合法性并返回属性类型
				String type = fieldOperate(column, name);
				param += type + " " + name + ", ";
				
				//获取setter语句
				setter.add(setterOperate(name, type));
				//比较器验证并获得where语句
				where += comparatorOpreter(column.attributeValue(comparator_), name);
			}
		}
		
		find.setParamSetter(setter);
		find.setParams(param.substring(0, param.length() - 2));
		
		return "where " + where.substring(5, where.length());
	}
	
	/**
	 * 验证query-column数据合法性
	 * @parm e column标签
	 * @throws FinderException
	 */
	private String fieldOperate(Element e, String name) throws FinderException {
		Node n = e.selectSingleNode("/build-mapping/entity[@name='" + holder.getEntity().getClassName() + "']/id[@name='" + name + "']");
		if(n == null) {
			n = e.selectSingleNode("/build-mapping/entity[@name='" + holder.getEntity().getClassName() + "']/property[@name='" + name + "']");
		}
		if(n == null) {
			throw new FinderException("query-column标签name属性值未能和entity属性对应:" + name, holder.getException());
		}
		
		return n.valueOf("@type");
	}
	
	/**
	 * 验证comparator并返回符合hibernate规范的where子句
	 * @throws FinderException
	 */
	private String comparatorOpreter(String cpt, String name) throws FinderException {
		String co = null;
		if(StringUtil.isNull(cpt)) {
			co = "=";
		}else {
			for (int i = 0; i < dbComparator.length; i++) {
				if(dbComparator[i].equals(cpt)) {
					co = cpt;
				}
			}
		}

		if(co == null) {
			throw new FinderException("query-column标签comparator属性非法:" + cpt, holder.getException());
		}else if("like".equals(co)) {
			return " and " + name + "like'%:" + name + "%'";
		}else {
			return " and " + name + co + ":" + name;
		}
	}
	
	/**
	 * 验证order-column并返回order语句
	 * @param order
	 * @return
	 * @throws FinderException
	 */
	@SuppressWarnings("unchecked")
	private String orderProcess(Element query) throws FinderException {
		Element order = query.element(order_by_);
		if(order == null) {
			return null;
		}
		
		List<Element> columns = order.elements(order_column_);
		
		if(columns == null || columns.size() == 0) {
			throw new FinderException("order标签未定义order-column子标签", holder.getException());
		}
		
		String orderBy = "order by ";
		for (Element column: columns) {
			String name = column.attributeValue(name_);
			String by = column.attributeValue(by_);
			//验证name属性合法性
			Node n = column.selectSingleNode("/build-mapping/entity[@name='" + holder.getEntity().getClassName() + "']/id[@name='" + name + "']");
			if(n == null) {
				n = column.selectSingleNode("/build-mapping/entity[@name='" + holder.getEntity().getClassName() + "']/property[@name='" + name + "']");
			}
			if(n == null) {
				throw new FinderException("query标签下的order-column子标签name属性值非法:" + name, holder.getException());
			}
			
			orderBy += name + " " + by + ", ";
		}
		
		return orderBy.substring(0, orderBy.length() - 2);
	}
}
